home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’97 / The Ugly Stick / source code / Text2Something.cp < prev    next >
Encoding:
Text File  |  1997-06-28  |  12.1 KB  |  570 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        Text2Something.cp
  3.  
  4.     Contains:    Sample Contextual Menu plugin
  5.  
  6.     Written by:    Kevin Hewitt & Tim Knox
  7.  
  8.     Copyright:    
  9.  
  10. */
  11.  
  12.  
  13. // Class Header
  14. #include "Text2Something.h"
  15.  
  16. // Mac OS Includes
  17. #include <AERegistry.h>
  18. #include <CodeFragments.h>
  19. #include <ContextualMenuPlugins.h>
  20. #include <Files.h>
  21. #include <TextEdit.h>
  22. #include <TextUtils.h>
  23. #include <Folders.h>
  24. // Utilities
  25.  
  26. // SOM Includes
  27. #include <som.xh>
  28.  
  29. enum
  30. {
  31.     kBeautifyCommand = 100,
  32.     kUglifyCommand = 101
  33. };
  34.  
  35. enum
  36. {
  37.     kFT_Unknown = 0,
  38.     kFT_Mac,
  39.     kFT_Dos
  40. };
  41.  
  42. // Function declarations
  43. extern pascal OSErr __initialize(CFragInitBlockPtr); // MetroWerks's default initializer
  44. extern pascal void __terminate(void);
  45. pascal OSErr Text2SomethingInitialize(CFragInitBlockPtr init); // our initializer
  46.  
  47. OSStatus AddCommandToAEDescList(ConstStr255Param inCommandString,
  48.     SInt32 inCommandID, AEDescList* ioCommandList);
  49. OSErr CoerceFiles(AEDescList* inFileList, SInt32 inCommandID);
  50. OSErr CoerceFile(FSSpec* file, SInt32 inCommandID);
  51. void Beautify (char * inp, char * outp, long * size, long * bytesParsed);
  52. void Uglify (char * inp, char * outp, long * size, long * bytesParsed);
  53. void CheckFile(FSSpec *inFileSpec, int *outFileType);
  54.  
  55.  
  56.  
  57. // ---------------------------------------------------------------------------
  58. // Text2SomethingInitialize
  59. // ---------------------------------------------------------------------------
  60. // Contextual Menu Plugins must register 
  61. // themselves in their init routine.
  62. // ---------------------------------------------------------------------------
  63.  
  64. pascal OSErr Text2SomethingInitialize(CFragInitBlockPtr init)
  65. {
  66. #pragma unused (init)
  67.  
  68.     // Initialize Metrowerks library
  69.     OSErr err = __initialize(init);
  70.     
  71.     // Register with SOM
  72.     if (err == noErr)
  73.         somNewClass(Text2Something);
  74.  
  75.     return err;
  76. }
  77.  
  78.  
  79.  
  80. // ---------------------------------------------------------------------------
  81. // Text2Something::Initialize
  82. // ---------------------------------------------------------------------------
  83.  
  84. OSStatus  Text2Something::Initialize(
  85.     Environment*,
  86.     FSSpec* inFileSpec)
  87. {
  88. #pragma unused (inFileSpec)
  89.     return noErr;
  90. }
  91.  
  92.  
  93.  
  94. // ---------------------------------------------------------------------------
  95. // Text2Something::ExamineContext
  96. // ---------------------------------------------------------------------------
  97.  
  98. OSStatus  Text2Something::ExamineContext(
  99.     Environment*,
  100.     AEDesc *inContextDescriptor,
  101.     SInt32 inTimeOutInTicks,
  102.     AEDescList* ioCommands,
  103.     Boolean* outNeedMoreTime)
  104. {
  105. #pragma unused(inTimeOutInTicks)
  106.  
  107.     OSStatus err = noErr;
  108.  
  109.     // Make sure the descriptor isn't null
  110.     if (inContextDescriptor != NULL)
  111.     {
  112.         AEDesc fileDesc = { typeNull, NULL };
  113.         
  114.         do
  115.         {
  116.             // Try to get an FSSpec out of the context descriptor; make sure to
  117.             // coerce it, cuz the app may have passed an object specifier.
  118.             err = ::AECoerceDesc(inContextDescriptor, typeFSS, &fileDesc);
  119.             if (err != noErr) break;
  120.             
  121.             // pull the FSSpec out of the descriptor
  122.             FSSpec theFileSpec;
  123.             ::BlockMoveData(*fileDesc.dataHandle, &theFileSpec,
  124.                 ::GetHandleSize(fileDesc.dataHandle));
  125.                 
  126.             // get the Catalog Info for this file
  127.             CInfoPBRec theInfo;
  128.             theInfo.hFileInfo.ioCompletion = NULL; // synchronous
  129.             theInfo.hFileInfo.ioNamePtr = theFileSpec.name;
  130.             theInfo.hFileInfo.ioVRefNum = theFileSpec.vRefNum;
  131.             theInfo.hFileInfo.ioFDirIndex = 0; // search for the named item
  132.             theInfo.hFileInfo.ioDirID = theFileSpec.parID;
  133.             err = ::PBGetCatInfoSync(&theInfo);
  134.             if (err != noErr) break;
  135.             
  136.             // see if we have a file and not a folder
  137.             if ((theInfo.hFileInfo.ioFlAttrib & ioDirMask) == 0)
  138.             {
  139.                 // Check the file's suffix
  140.                 OSType suffix = 0;
  141.                 OSType fileType = theInfo.hFileInfo.ioFlFndrInfo.fdType;
  142.                 OSType fileCreator = theInfo.hFileInfo.ioFlFndrInfo.fdCreator;
  143.                 if (*theInfo.hFileInfo.ioNamePtr > 3)
  144.                 {
  145.                     suffix = *(OSType*)&theInfo.hFileInfo.ioNamePtr[*theInfo.hFileInfo.ioNamePtr - 3];
  146.                     ::UppercaseText((Ptr) &suffix, 4, smSystemScript);
  147.                 }
  148.                 
  149.                 if (suffix == '.TXT' || fileType == 'TEXT')
  150.                 {
  151.                     int fileType;
  152.                     // Add this command to the command list
  153.                     CheckFile(&theFileSpec, &fileType);
  154.                     switch (fileType)
  155.                     {
  156.                         case kFT_Unknown:
  157.                             break;
  158.                         case kFT_Mac:
  159.                             err = ::AddCommandToAEDescList("\pUglify", kUglifyCommand, ioCommands);
  160.                             break;
  161.                         case kFT_Dos:
  162.                             err = ::AddCommandToAEDescList("\pBeautify", kBeautifyCommand, ioCommands);
  163.                             break;
  164.                     }
  165.                     if (err != noErr) break;
  166.                 }
  167.             }
  168.         }
  169.         while (false);
  170.         
  171.         // clean up after ourself
  172.         ::AEDisposeDesc(&fileDesc);
  173.     }
  174.     
  175.     *outNeedMoreTime = false;
  176.     
  177.     return err;
  178. }
  179.  
  180.  
  181.  
  182. // ---------------------------------------------------------------------------
  183. // Text2Something::HandleSelection
  184. // ---------------------------------------------------------------------------
  185.  
  186. OSStatus Text2Something::HandleSelection(
  187.     Environment*,
  188.     AEDesc *inContextDescriptor,
  189.     SInt32 inCommandID)
  190. {
  191. #pragma unused (inContextDescriptor, inCommandID)
  192.  
  193.     // here is where you would actually carry out the action that the user
  194.     // requested.
  195.     
  196.     return CoerceFiles(inContextDescriptor, inCommandID);
  197. //    return noErr;
  198. }
  199.  
  200.  
  201.  
  202. // ---------------------------------------------------------------------------
  203. // Text2Something::PostMenuCleanup
  204. // ---------------------------------------------------------------------------
  205.  
  206. OSStatus Text2Something::PostMenuCleanup(
  207.     Environment*)
  208. {
  209.     // Nothing to clean up here
  210.     
  211.     return noErr;
  212. }
  213.  
  214.  
  215.  
  216. // ---------------------------------------------------------------------------
  217. // AddCommandToAEDescList
  218. // ---------------------------------------------------------------------------
  219.  
  220. OSStatus AddCommandToAEDescList(
  221.     ConstStr255Param inCommandString,
  222.     SInt32 inCommandID,
  223.     AEDescList* ioCommandList)
  224. {
  225.     OSStatus theError = noErr;
  226.     
  227.     AERecord theCommandRecord = { typeNull, NULL };
  228.     
  229.     do
  230.     {
  231.         // create an apple event record for our command
  232.         theError = ::AECreateList(NULL, 0, true, &theCommandRecord);
  233.         if (theError != noErr) break;
  234.         
  235.         // stick the command text into the aerecord
  236.         theError = ::AEPutKeyPtr(&theCommandRecord, keyAEName, typeChar,
  237.             &inCommandString[1], inCommandString[0]);
  238.         if (theError != noErr) break;
  239.             
  240.         // stick the command ID into the AERecord
  241.         theError = ::AEPutKeyPtr(&theCommandRecord, keyContextualMenuCommandID, typeLongInteger,
  242.             &inCommandID, sizeof (inCommandID));
  243.         if (theError != noErr) break;
  244.         
  245.         // stick this record into the list of commands that we are passing back to CMM
  246.         theError = ::AEPutDesc(ioCommandList, // the list we're putting our command into
  247.                         0, // stick this command onto the end of our list
  248.                         &theCommandRecord); // the command I'm putting into the list
  249.         
  250.     } while (false);
  251.     
  252.     // clean up after ourself; dispose of the AERecord
  253.     ::AEDisposeDesc(&theCommandRecord);
  254.  
  255.     return theError;
  256. }
  257.  
  258. OSErr CoerceFiles(AEDescList* inFileList, SInt32 inCommandID)
  259. {
  260.     long items, x;
  261.     AEDesc fileDesc = { typeNull, NULL };
  262.     AEKeyword returnedKeyword;
  263.     FSSpec theFileSpec;
  264.     OSErr err;
  265.  
  266.     ::AECountItems(inFileList, &items);
  267.     for (x=1; x<= items; x++)
  268.     {
  269.         ::AEGetNthDesc(inFileList, x, typeFSS, &returnedKeyword, &fileDesc);
  270.         ::BlockMoveData(*fileDesc.dataHandle, &theFileSpec, ::GetHandleSize(fileDesc.dataHandle));
  271.         err = CoerceFile(&theFileSpec, inCommandID);
  272.         ::AEDisposeDesc(&fileDesc);
  273.         if (err != noErr)
  274.             break;
  275.     }
  276.     return err;
  277. }
  278.  
  279.  
  280.  
  281.  
  282. OSErr CoerceFile(FSSpec* inFileSpec, SInt32 inCommandID)
  283. {
  284.     short    inref, outref;
  285.     long    insz, outsz, intotsz = 0;
  286.     short    foundvol;
  287.     long    founddir;
  288.     long    prevFilePos;
  289.     long    bytesParsed;
  290.     long    bytesWritten;
  291.     FSSpec    outfs;
  292.  
  293.     OSErr anErr = FindFolder (0, kDesktopFolderType, true, &foundvol, &founddir);
  294.     if (anErr != noErr)
  295.         goto GotAnError;
  296.     
  297.     anErr = FSMakeFSSpec (foundvol, founddir, "\ptemp work file", &outfs);
  298.     if (anErr != noErr) {
  299.         if (anErr != fnfErr)
  300.             goto GotAnError;
  301.         anErr = FSpCreate (&outfs, 'R*ch', 'TEXT', 0);
  302.         if (anErr != noErr)
  303.             goto GotAnError;
  304.     };
  305.     
  306.     Handle    inwork, outwork;
  307.     inwork = NewHandle (4096L);
  308.     outwork = NewHandle (4096L);
  309.     
  310.     HLockHi (inwork);
  311.     HLockHi (outwork);
  312.     
  313.     anErr = FSpOpenDF (inFileSpec, fsRdPerm, &inref);
  314.     if (anErr != noErr)
  315.         goto GotAnError;
  316.     
  317.     anErr = FSpOpenDF (&outfs, fsWrPerm, &outref);
  318.     if (anErr != noErr)
  319.         goto GotAnError;
  320.         
  321.     anErr = GetEOF (inref, &intotsz);
  322.     if (anErr != noErr)
  323.         goto GotAnError;
  324.     
  325.     prevFilePos = 0L;
  326.     bytesWritten = 0L;
  327.     while (intotsz > 0) {
  328.         insz = 2048L;
  329.         anErr = FSRead (inref, &insz, *inwork);
  330.         if ((anErr != noErr) && (anErr != eofErr))
  331.             break;
  332.         outsz = insz;
  333.         switch (inCommandID)
  334.         {
  335.             case kBeautifyCommand:
  336.                 Beautify (*inwork, *outwork, &outsz, &bytesParsed);
  337.                 break;
  338.             case kUglifyCommand:
  339.                 Uglify (*inwork, *outwork, &outsz, &bytesParsed);
  340.                 break;
  341.         }
  342.         prevFilePos += bytesParsed;
  343.         anErr = ::SetFPos(inref, fsFromStart, prevFilePos);
  344.         if (anErr != noErr)
  345.             break;
  346.         anErr = FSWrite (outref, &outsz, *outwork);
  347.         bytesWritten += outsz;
  348.         if (anErr != noErr)
  349.             break;
  350.         intotsz -= bytesParsed;
  351.     };
  352.     if (anErr != noErr)
  353.         goto GotAnError;
  354.  
  355.     ::SetEOF(outref, bytesWritten);
  356.     ::FSClose(outref);
  357.     ::FSClose(inref);
  358.     anErr = FSpExchangeFiles (inFileSpec, &outfs);
  359.     if (anErr != noErr)
  360.         goto GotAnError;
  361.     
  362.     anErr = FSpDelete (&outfs);
  363.     if (anErr != noErr)
  364.         goto GotAnError;
  365.     
  366. GotAnError:
  367.     if (inwork)
  368.         DisposeHandle (inwork);
  369.     if (outwork)
  370.         DisposeHandle (outwork);
  371.     
  372.     return anErr;
  373. }
  374.  
  375. void Beautify (char * inp, char * outp, long * size, long * bytesParsed)
  376. {
  377.     char    c;
  378.     int        numOfPeriods = 0;
  379.     long    savesz, curpos;
  380.     long    curOutPos;
  381.     Boolean    breaksoon, seencr, seenquote, seenstop, seenblank;
  382.     
  383.     
  384.     breaksoon = seencr = seenquote = seenstop = seenblank = false;
  385.     
  386.     savesz = *size;
  387.     *size = 0;
  388.     curOutPos = *size;
  389.     curpos = curOutPos;
  390.     *bytesParsed = 0;
  391.     
  392.     
  393.     while (curpos <= savesz) {
  394.         c = inp [curpos++];
  395.     
  396.         if (c == 0x0d)
  397.         {
  398.             seencr = true;
  399.         }
  400.         else
  401.         {
  402.             if (seencr)
  403.             {
  404.                 seencr = false;
  405.                 if (c == 0x0a)
  406.                     c = inp[curpos++];
  407.                 if (c == 0x0d)
  408.                     seencr = true;
  409.                 if (breaksoon)
  410.                     break;
  411.             }
  412.         }
  413.                 
  414.         if (c == '"') {
  415.             if (!seenquote)
  416.                 c = '“';
  417.             else
  418.                 c = '”';
  419.             seenquote = !seenquote;
  420.         }
  421.         
  422.         if (c == '\'')
  423.             c = '’';
  424.         
  425.         if (seenstop == true)
  426.         {
  427.             if (numOfPeriods == 3)
  428.             {
  429.                 if (c != '.')
  430.                 {
  431.                     curOutPos -= 3;
  432.                     outp[curOutPos++] = '…';
  433.                 }
  434.                 seenstop = false;
  435.             }
  436.         }
  437.         
  438.         if ((seenblank) && c == ' ')
  439.             continue;
  440.         
  441.         if (c == ' ')
  442.             seenblank = true;
  443.         else
  444.             seenblank = false;
  445.         
  446.         outp [curOutPos++] = c;
  447.         
  448.         if (c == '.')
  449.         {
  450.             numOfPeriods++;
  451.             seenstop = true;
  452.         }
  453.         else
  454.             numOfPeriods = 0;
  455.             
  456.         if (curpos > 1920L)
  457.             breaksoon = true;
  458.     };
  459.     *size = curOutPos - 1;
  460.     *bytesParsed = curpos - 1;
  461.     
  462. //    if (breaksoon == true)
  463. //        BlockMove ((inp + curpos), inp, (savesz - curpos));
  464. }
  465.  
  466. void Uglify (char * inp, char * outp, long * size, long * bytesParsed)
  467. {
  468.     char    c;
  469.     int        numOfPeriods = 0;
  470.     long    savesz, curpos;
  471.     long    curOutPos;
  472.     Boolean    breaksoon, seencr, seenstop, seenblank;
  473.     
  474.     
  475.     breaksoon = seencr = seenstop = seenblank = false;
  476.     
  477.     savesz = *size;
  478.     *size = 0;
  479.     curOutPos = *size;
  480.     curpos = curOutPos;
  481.     *bytesParsed = 0;
  482.     
  483.     
  484.     while (curpos <= savesz) {
  485.         c = inp [curpos++];
  486.     
  487.         if (seencr)
  488.         {
  489.             seencr = false;
  490.             if (c != 0x0a)
  491.                 outp [curOutPos++] = 0x0a;
  492.             if (breaksoon)
  493.                 break;
  494.         }
  495.         if (c == 0x0d)
  496.         {
  497.             seencr = true;
  498.         }
  499.                 
  500.         if (c == '“')
  501.             c = '"';
  502.         if (c == '”')
  503.             c = '"';
  504.         
  505.         if (c == '’')
  506.             c = '\'';
  507.         
  508.         if (c == '…')
  509.         {
  510.             outp [curOutPos++] = '.';
  511.             outp [curOutPos++] = '.';
  512.             outp [curOutPos++] = '.';
  513.             continue;
  514.         }
  515.         
  516.         outp [curOutPos++] = c;
  517.         
  518.             
  519.         if (curpos > 1920L)
  520.             breaksoon = true;
  521.     };
  522.     *size = curOutPos - 1;
  523.     *bytesParsed = curpos - 1;
  524.     
  525. //    if (breaksoon == true)
  526. //        BlockMove ((inp + curpos), inp, (savesz - curpos));
  527. }
  528.  
  529. void CheckFile(FSSpec *inFileSpec, int *outFileType)
  530. {
  531.     short    refNum;
  532.     OSErr    err;
  533.     long    bytes;
  534.     char    buf[255];
  535.     char    *ptr;
  536.     int        LoopIt = 2;
  537.     
  538.     *outFileType = kFT_Unknown;
  539.     err = ::FSpOpenDF(inFileSpec, fsRdPerm, &refNum);
  540.     if (err == noErr)
  541.     {
  542.         do {
  543.             LoopIt--;
  544.             bytes = sizeof(buf);
  545.             err = ::FSRead(refNum, &bytes, buf);
  546.             if (err == noErr || bytes > 0)
  547.             {
  548.                 ptr = &buf[0];
  549.                 for (; bytes; bytes--)
  550.                 {
  551.                     if (*ptr == 0x0d)
  552.                     {
  553.                         ptr++;
  554.                         if (*ptr == 0x0a)
  555.                             *outFileType = kFT_Dos;
  556.                         else
  557.                             *outFileType = kFT_Mac;
  558.                         bytes = 1;
  559.                         LoopIt = 0;
  560.                     }
  561.                     ptr++;
  562.                 }
  563.             }
  564.             else
  565.                 LoopIt = 0;
  566.         } while (LoopIt);
  567.     }
  568.     ::FSClose(refNum);
  569.     return;
  570. }